Add `lto` option to profiles.
authorAndrew Gallant <jamslam@gmail.com>
Thu, 13 Nov 2014 02:20:44 +0000 (21:20 -0500)
committerAndrew Gallant <jamslam@gmail.com>
Thu, 13 Nov 2014 02:20:44 +0000 (21:20 -0500)
Closes #759.

src/cargo/core/manifest.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/util/toml.rs
tests/test_cargo_compile.rs

index eebed5f4a99389eed3881640de6987570b16b27a..0e96a8d7b0f73f2cd0f51c9e89bb0f329fd9ead4 100644 (file)
@@ -126,6 +126,7 @@ pub enum TargetKind {
 pub struct Profile {
     env: String, // compile, test, dev, bench, etc.
     opt_level: uint,
+    lto: bool,
     codegen_units: Option<uint>,    // None = use rustc default
     debug: bool,
     rpath: bool,
@@ -143,6 +144,7 @@ impl Profile {
         Profile {
             env: String::new(),
             opt_level: 0,
+            lto: false,
             codegen_units: None,
             debug: false,
             rpath: false,
@@ -160,6 +162,7 @@ impl Profile {
         Profile {
             env: "compile".to_string(), // run in the default environment only
             opt_level: 0,
+            lto: false,
             debug: true,
             .. Profile::default()
         }
@@ -179,6 +182,7 @@ impl Profile {
         Profile {
             env: "bench".to_string(),
             opt_level: 3,
+            lto: false,
             test: true,
             dest: Some("release".to_string()),
             .. Profile::default()
@@ -189,6 +193,7 @@ impl Profile {
         Profile {
             env: "release".to_string(),
             opt_level: 3,
+            lto: false,
             dest: Some("release".to_string()),
             .. Profile::default()
         }
@@ -236,6 +241,10 @@ impl Profile {
         self.opt_level
     }
 
+    pub fn get_lto(&self) -> bool {
+        self.lto
+    }
+
     pub fn get_codegen_units(&self) -> Option<uint> {
         self.codegen_units
     }
@@ -261,6 +270,11 @@ impl Profile {
         self
     }
 
+    pub fn lto(mut self, lto: bool) -> Profile {
+        self.lto = lto;
+        self
+    }
+
     pub fn codegen_units(mut self, units: Option<uint>) -> Profile {
         self.codegen_units = units;
         self
@@ -315,6 +329,7 @@ impl<H: hash::Writer> hash::Hash<H> for Profile {
         // to the actual hash of a profile.
         let Profile {
             opt_level,
+            lto,
             codegen_units,
             debug,
             rpath,
@@ -332,7 +347,8 @@ impl<H: hash::Writer> hash::Hash<H> for Profile {
 
             custom_build: _,
         } = *self;
-        (opt_level, codegen_units, debug, rpath, for_host, dest, harness).hash(into)
+        (opt_level, lto, codegen_units, debug,
+         rpath, for_host, dest, harness).hash(into)
     }
 }
 
index 89f4217daa541eafd70974c19302e3e6e4da0b1e..88df60d6d5b8c37ae7019357dff29b6dd0a7354f 100644 (file)
@@ -320,6 +320,7 @@ fn compile_custom_old(pkg: &Package, cmd: &str,
                      .env("TARGET", Some(cx.target_triple()))
                      .env("DEBUG", Some(profile.get_debug().to_string()))
                      .env("OPT_LEVEL", Some(profile.get_opt_level().to_string()))
+                     .env("LTO", Some(profile.get_lto().to_string()))
                      .env("PROFILE", Some(profile.get_env()));
     for arg in cmd {
         p = p.arg(arg);
@@ -549,10 +550,16 @@ fn build_base_args(cx: &Context,
     if profile.get_opt_level() != 0 {
         cmd = cmd.arg("--opt-level").arg(profile.get_opt_level().to_string());
     }
-
-    match profile.get_codegen_units() {
-        Some(n) => cmd = cmd.arg("-C").arg(format!("codegen-units={}", n)),
-        None => {},
+    if target.is_bin() && profile.get_lto() {
+        cmd = cmd.args(["-C", "lto"]);
+    } else {
+        // @alexchrichton says that there may be some restrictions with LTO
+        // and codegen-units, so that we should only add codegen units when
+        // LTO is not used.
+        match profile.get_codegen_units() {
+            Some(n) => cmd = cmd.arg("-C").arg(format!("codegen-units={}", n)),
+            None => {},
+        }
     }
 
     if profile.get_debug() {
index ffdaf9b8a956d9e31e2ee81f50058377e1abb3f2..ea2797ab25f96fe2704f664f97bc7d3300d0d108 100644 (file)
@@ -230,6 +230,7 @@ pub struct TomlProfiles {
 #[deriving(Decodable, Clone, Default)]
 pub struct TomlProfile {
     opt_level: Option<uint>,
+    lto: Option<bool>,
     codegen_units: Option<uint>,
     debug: Option<bool>,
     rpath: Option<bool>,
@@ -673,11 +674,12 @@ fn normalize(libs: &[TomlLibTarget],
             None => return profile,
         };
         let opt_level = toml.opt_level.unwrap_or(profile.get_opt_level());
+        let lto = toml.lto.unwrap_or(profile.get_lto());
         let codegen_units = toml.codegen_units;
         let debug = toml.debug.unwrap_or(profile.get_debug());
         let rpath = toml.rpath.unwrap_or(profile.get_rpath());
-        profile.opt_level(opt_level).codegen_units(codegen_units).debug(debug)
-               .rpath(rpath)
+        profile.opt_level(opt_level).lto(lto).codegen_units(codegen_units)
+               .debug(debug).rpath(rpath)
     }
 
     fn target_profiles(target: &TomlTarget, profiles: &TomlProfiles,
index d8b034f4d29a24ca1b3e99fdd106142d0fee3e15..43c696a98f2088b98da13fc6fafbff3e1d2f420b 100644 (file)
@@ -731,6 +731,36 @@ test!(missing_lib_and_bin {
                                      must be present\n"));
 })
 
+test!(lto_build {
+    let mut p = project("foo");
+    p = p
+        .file("Cargo.toml", r#"
+            [package]
+
+            name = "test"
+            version = "0.0.0"
+            authors = []
+            lto = true
+        "#)
+        .file("src/main.rs", "fn main() {}");
+    assert_that(p.cargo_process("build").arg("-v"),
+                execs().with_status(0).with_stdout(format!("\
+{compiling} test v0.0.0 ({url})
+{running} `rustc {dir}{sep}src{sep}lib.rs --crate-name test --crate-type bin -g \
+        -C lto \
+        -C metadata=[..] \
+        -C extra-filename=-[..] \
+        --out-dir {dir}{sep}target \
+        --dep-info [..] \
+        -L {dir}{sep}target \
+        -L {dir}{sep}target{sep}deps`
+",
+running = RUNNING, compiling = COMPILING, sep = path::SEP,
+dir = p.root().display(),
+url = p.url(),
+)));
+})
+
 test!(verbose_build {
     let mut p = project("foo");
     p = p